package com.hxk.jvm;

import java.util.ArrayList;
import java.util.List;

/**
 * JVM堆内存，
 * 1、按照逻辑分类分为：年轻代，老年代、永久代（jdk7之前，jdk8叫元空间）
 * 2、按照物理分类分为：年轻代和养老代
 * 3、java垃圾回收机制GC主要清理的区域
 * 一：年轻代又按照8比1比1的比例分为：
 *      1、Eden（伊甸原区）8
 *      2、From（幸存者0区，From区）1
 *      3、To（幸存者1区，To区）1
 *   当Eden区满时会发生YGC，当养老区满时会发生FGC
 *  JVM的调优就是调整堆内存的大小，通过设置jvm的初始大小和最大内存来实现，比如设置调整jvm的初始堆内存和最大堆内存为1024m，调整命令如下：
 *      -Xms1024m -Xmx1024m -XX:+PrintGCDetails 【注意在生产环境要求jvm的初始大小和最大内存配置一样大，这样可以减少在扩容的时候出现卡顿和一些未知的问题】
 *     运行结果：
 *     Heap
         PSYoungGen      total 305664K, used 15729K [0x00000000eab00000, 0x0000000100000000, 0x0000000100000000)
             eden space 262144K, 6% used [0x00000000eab00000,0x00000000eba5c420,0x00000000fab00000)
             from space 43520K, 0% used [0x00000000fd580000,0x00000000fd580000,0x0000000100000000)
             to   space 43520K, 0% used [0x00000000fab00000,0x00000000fab00000,0x00000000fd580000)
         ParOldGen       total 699392K, used 0K [0x00000000c0000000, 0x00000000eab00000, 0x00000000eab00000)
            object space 699392K, 0% used [0x00000000c0000000,0x00000000c0000000,0x00000000eab00000)
         Metaspace       used 3360K, capacity 4496K, committed 4864K, reserved 1056768K
            class space    used 369K, capacity 388K, committed 512K, reserved 1048576K
    JVM的gc垃圾回收算法有几种：
        有四种：
            1、引用计算算法，适用于年轻代，优点：效率高，缺点：消耗内存，因为本身要产生一个引用计算器占用内空间，较难处理嵌套引用
            2、复制算法，使用于年轻代，优点：效率高，不会产生内存碎片，缺点：空间要求高【推荐在年轻代使用该算法】
            3、标记清除法，适用于老年代，优点：效率高，缺点：有内存碎片
            4、标记清除整理法，适用于老年代，优点：没有内存碎片，缺点：耗时 【推荐在养老区使用该算法】
    最好的gc垃圾算法是，分代收集算法，分代收集算法就是，不同的代使用不同的算法，既年轻代使用【复制算法】，老年代使用【标记清除整理法】
    jvm垃圾回收过程：
     [GC (Allocation Failure) [PSYoungGen: 261369K->42712K(305664K)] 261369K->254691K(1005056K), 0.1257359 secs] [Times: user=0.16 sys=0.11, real=0.13 secs]
     [GC (Allocation Failure) [PSYoungGen: 304856K->42744K(305664K)] 516835K->515847K(1005056K), 0.0993039 secs] [Times: user=0.06 sys=0.25, real=0.10 secs]
     [Full GC (Ergonomics) [PSYoungGen: 42744K->0K(305664K)] [ParOldGen: 473103K->515719K(699392K)] 515847K->515719K(1005056K), [Metaspace: 3441K->3441K(1056768K)], 0.1097326 secs] [Times: user=0.22 sys=0.03, real=0.11 secs]
     [Full GC (Ergonomics) [PSYoungGen: 262144K->70657K(305664K)] [ParOldGen: 515719K->699019K(699392K)] 777863K->769676K(1005056K), [Metaspace: 3442K->3442K(1056768K)], 0.0821929 secs] [Times: user=0.14 sys=0.09, real=0.08 secs]
     [Full GC (Ergonomics) [PSYoungGen: 262144K->261128K(305664K)] [ParOldGen: 699019K->699015K(699392K)] 961163K->960144K(1005056K), [Metaspace: 3442K->3442K(1056768K)], 0.0623902 secs] [Times: user=0.14 sys=0.00, real=0.06 secs]
     [Full GC (Allocation Failure) [PSYoungGen: 261128K->261128K(305664K)] [ParOldGen: 699015K->698997K(699392K)] 960144K->960126K(1005056K), [Metaspace: 3442K->3442K(1056768K)], 0.0574425 secs] [Times: user=0.14 sys=0.00, real=0.06 secs]
    java代码直接使用System.gc();是手动唤醒jvm的垃圾回收机制GC。但是不是立刻执行，因为gc是java的一个底层线程，而线程的调度不由java语言控制，而是有系统控制，所以不会立刻执行
 */
public class JVMHeapCase {
    public static void main(String[] args) {
        //获取系统cpu的核数
        System.out.println(Runtime.getRuntime().availableProcessors());
        //jvm在当前系统实际的内存
        long totalMemory = Runtime.getRuntime().totalMemory();
        //jvm最大系统内存
        long maxMemory = Runtime.getRuntime().maxMemory();

        System.out.println("jvm初始内存（-Xms）："+totalMemory+"字节，"+(totalMemory/1024/1024)+"MB");

        System.out.println("jvm最大内存（-Xmx）："+maxMemory+"字节，"+(maxMemory/1024/1024)+"MB");

        //引发OOM的代码事例
        List<byte[]> datas = new ArrayList<byte[]>();
        while ( true ) {
            datas.add(new byte[1024 * 1024]);
        }
    }
}
